"use strict"

module.exports = function(sequelize, DataTypes) {
  var _       = require('lodash')
    , debug   = require('debug')('qywx-api-models');

  var CorpWechatAccessToken = sequelize.define("CorpWechatAccessToken", {
    corpId: {
      type: DataTypes.STRING(128)
      ,allowNull: false
      ,unique: true
      ,field: "corp_id"
    }
    ,token: { type: DataTypes.STRING(1024), allowNull: false  }
    ,expiresAt: { type: DataTypes.DATE, allowNull: false, field: "expires_at" }
    ,lockedBy: { type: DataTypes.STRING(128), allowNull: true, field: "locked_by" }
    ,lockedAt: { type: DataTypes.DATE, field: "locked_at" }
  }, {
    getterMethods   : {
      isExpiring : function()  { return !!(this.expiresAt < (_.now() + 120000)) }
    },
    classMethods: {
      getToken: function(corpId, done){
        this.findOne({
          where: { corpId: corpId, expiresAt: { $gt: _.now() } }
        })
        .then(function(instance){
          return done(null, instance);
        })
        .catch(function(err){
          debug(err);
          return done(err, null);
        })
      }
      ,updateToken: function(corpId, token, expiresIn){
        return this.upsert({
          corpId: corpId
          ,token: token
          ,expiresAt: _.now() + (expiresIn * 1000)  /* 7200s - 300s means 5 minutes earlier then actual expire */
          ,lockedAt: null
          ,lockedBy: null
        });
      }
      ,initToken: function(corpId){
        return this.create({
          corpId: corpId,
          token: "",
          expiresAt: _.now(),
          lockedBy: process.pid,
          lockedAt: _.now()
        });
      }
      ,lockForUpdate: function(corpId){
        console.error("=====> lock for update at: ", _.now());
        var model = this;
        var lockedAt = _.now();
        return model.update({
            lockedBy: process.pid,
            lockedAt: lockedAt
          }, {
            where: {
              corpId: corpId,
              $or: [
                { lockedAt: { $eq: null } },
                { lockedAt: { $lt: new Date(_.now() - 60 * 1000) } }
              ]
            },
            returning: true
          })
          .then(function(results){
            console.error("=====> lock for update lock it : ", results);
            return model.findOne({
              where: {
                corpId: corpId,
                lockedBy: _.toString(process.pid)
              }
            })
          });
      }
      ,unlockAndUpdate: function(corpId, token, expiresIn){
        var model = this;
        return model.update({
          corpId: corpId,
          token: token,
          expiresAt: _.now() + (expiresIn * 1000),
          lockedBy: null,
          lockedAt: null
        }, {
          where: {
            corpId: corpId,
            lockedBy: _.toString(process.pid)
          },
          returning: true
        })
        .then(function(results){
          return model.findOne({
            where: {
              corpId: corpId
            }
          })
        });
      }
    },
    instanceMethods: {

    }
});


  return CorpWechatAccessToken;
};
